#include <iostream>
#include <cstring>
#include <cstdlib>

#include "MLP.h"
#include "Perceptron.h"
#include "Holdout.h"
#include "DataSet.h"
#include "Defines.h"
#include "CSVFile.h"

int createMLP(int argc, char *argv[]);
int trainMLP(int argc, char *argv[]);
int testMLP(int argc, char *argv[]);
int trainTestMLP(int argc, char *argv[]);
int infoMLP(int argc, char *argv[]);
int infoInput(int argc, char *argv[]);
int infoOutput(int argc, char *argv[]);

int main(int argc, char *argv[])
{
    if(argc == 1)
    {
        cerr << "Usage mode: " << argv[0] << " [create|train|test|info-perc|info-in|info-out] ..." << endl;
        return EXIT_FAILURE;
    }

    srand(time(NULL));

    if(!strcmp(argv[1], "create"))
        return createMLP(argc, argv);

    else if(!strcmp(argv[1], "train"))
        return trainMLP(argc, argv);

    else if(!strcmp(argv[1], "test"))
        return testMLP(argc, argv);

    else if(!strcmp(argv[1], "train-test"))
        return trainTestMLP(argc, argv);

    else if(!strcmp(argv[1], "info-mlp"))
        return infoMLP(argc, argv);

    else if(!strcmp(argv[1], "info-in"))
        return infoInput(argc, argv);

    else if(!strcmp(argv[1], "info-out"))
        return infoOutput(argc, argv);

    else
    {
        cerr << "Usage mode: " << argv[0] << " [create|train|test|train-test|info-perc|info-in|info-out] ..." << endl;
        return EXIT_FAILURE;
    }
}

int createMLP(int argc, char *argv[])
{
    if(argc < 5)
    {
        cerr << "Usage mode: " << argv[0] << " create <output file> <number of inputs> " <<
                "<number of neurons on each layer> " << endl;
        return EXIT_FAILURE;
    }

    uint nInVars = atoi(argv[3]);

    vuint nNeurons;
    for(int i = 4; i < argc; i++)
        nNeurons.push_back(atoi(argv[i]));

    MLP mlp(nInVars, nNeurons);
    mlp.saveToFile(argv[2]);

    return EXIT_SUCCESS;
}

int trainMLP(int argc, char *argv[])
{
    if(argc != 7)
    {
        cerr << "Usage mode: " << argv[0] << " train <mlp file> <input file> <output file> " <<
                "<maximum tolerance> <maximum number of iterations>" << endl;
        return EXIT_FAILURE;
    }

    MLP mlp(argv[2]);
    DataSet ds(argv[3], INPUT);
    double tolerance = atof(argv[5]);
    uint maxIt = atoi(argv[6]);

    mlp.train(ds, tolerance, maxIt);
    mlp.saveToFile(argv[2]);
    ds.saveToFile(argv[4]);

    return EXIT_SUCCESS;
}

int testMLP(int argc, char *argv[])
{
    if(argc != 6)
    {
        cerr << "Usage mode: " << argv[0] << " test <mlp file> <input file> <output file> " <<
                "<maximum tolerance>" << endl;
        return EXIT_FAILURE;
    }

    MLP mlp(argv[2]);
    DataSet ds(argv[3], INPUT);
    double tolerance = atof(argv[5]);

    mlp.test(ds, tolerance);
    ds.saveToFile(argv[4]);

    return EXIT_SUCCESS;
}

int trainTestMLP(int argc, char *argv[])
{
    if(argc != 7)
    {
        cerr << "Usage mode: " << argv[0] << " train-test <mlp file> <input file> <output file> " <<
                "<maximum tolerance> <maximum number of iterations>" << endl;
        return EXIT_FAILURE;
    }
    
    MLP mlp(argv[2]);
    DataSet ds(argv[3], INPUT);
    double tolerance = atof(argv[5]);
    uint maxIt = atoi(argv[6]);

    Holdout h(ds);
    h.execute(mlp, tolerance, maxIt);
    mlp.saveToFile(argv[2]);
    ds.saveToFile(argv[4]);

    return EXIT_SUCCESS;
}

int infoMLP(int argc, char *argv[])
{
    if(argc != 3)
    {
        cerr << "Usage mode: " << argv[0] << " info-mlp <mlp file>" << endl;
        return EXIT_FAILURE;
    }

    MLP mlp(argv[2]);

    return EXIT_SUCCESS;
}

int infoInput(int argc, char *argv[])
{
    if(argc != 3)
    {
        cerr << "Usage mode: " << argv[0] << " info-in <input file>" << endl;
        return EXIT_FAILURE;
    }

    DataSet ds(argv[2], INPUT);

    return EXIT_SUCCESS;
}

int infoOutput(int argc, char *argv[])
{
    if(argc != 3)
    {
        cerr << "Usage mode: " << argv[0] << " info-out <output file>" << endl;
        return EXIT_FAILURE;
    }

    DataSet ds(argv[2], OUTPUT);

    return EXIT_SUCCESS;
}

